/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.brainstretch.models.document;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.brainstretch.recommend.TermWeight;

/**
 *
 * @author mrodaitis
 */
public class DocumentVector {

    private Map<Term, Double> termWeights;
    
    private double length;
    
    protected DocumentVector(){        
        termWeights = new HashMap<Term, Double>();
    }
    
    public DocumentVector(List<Posting> postings) {
        this();
        for(Posting posting: postings){
            addTermWeight(posting.getTerm(), getAdjustedTFIDFScore(posting));
        }
        initAndNormalize();
    }
   
    private void initAndNormalize(){
        length = calcLength();
        normalize();
    }
    
    private double getTFIDFScore(TermWeight tWeight){
        return tWeight.getWeight() * tWeight.getTerm().getInverseDocumentFreq();
    }
    
    private double getTFIDFScore(Posting posting){
        return posting.getFrequency() * posting.getTerm().getInverseDocumentFreq();
    }
    
    private double getAdjustedTFIDFScore(Posting posting){
        
        return 1.0 + Math.log(getTFIDFScore(posting));
    }
    
    private void addTermWeight(Term term, double weight){
        Double existing = getWeight(term);
        existing += weight;
        termWeights.put(term, existing);        
    }
    
    public void adjustWeight(Term term, double weight){
        addTermWeight(term, weight);    
    }

    public void add(DocumentVector other){
        for(Term term: other.termWeights.keySet()){
            adjustWeight(term, other.getWeight(term));
        }
    }
    
    public void scale(double scalar){
        for(Term term: termWeights.keySet()){
            termWeights.put(term, termWeights.get(term) * scalar);
        }
    }
    
    private double calcLength() {
        double len = 0;
        for(Double d: termWeights.values()){
            len += d * d;
        }
        len = Math.sqrt(len);
        return len;
    }

    private void normalize() {
        for(Term term: termWeights.keySet()){
            double weight = termWeights.get(term);
            termWeights.put(term, weight/length);
        }
    }    
    
    public double getWeight(Term term){
        Double weight = termWeights.get(term);
        if(weight == null){
            weight = 0d;
        }
        return weight;
    }
    
    public Set<Term> getTerms(){
        return termWeights.keySet();
    }
    
    public double cosineSimilarity(DocumentVector other){
        Set<Term> myTerms = this.getTerms();
        Set<Term> otherTerms = other.getTerms();
        
        double product = 0;
        
        for(Term term: myTerms){
            if(otherTerms.contains(term)){
                product += this.getWeight(term) * other.getWeight(term);
            }
        }
        
        return product;
    }
}
